package com.tywj.panda.customer.common.bus

import androidx.annotation.MainThread
import androidx.collection.ArrayMap
import androidx.lifecycle.*
import com.tywj.lib.lifecycle.extension.post


/**
 * <pre>
 *     author : June Yang
 *     time   : 2020/5/16
 *     desc   : 使用LiveData实现的消息总线
 *     version: 1.0.0
 * </pre>
 */
class LiveEventBus {

    companion object {
        @JvmStatic
        private val instance by lazy { LiveEventBus() }

        @JvmStatic
        fun <T> get(key: String): Event<T> {
            return instance.getEvent(key)
        }
    }

    private val bus = ArrayMap<String, Event<*>>()

    fun <T> getEvent(key: String): Event<T> {
        if (!bus.containsKey(key)) {
            bus[key] =
                LiveEvent<T>(key)
        }
        @Suppress("UNCHECKED_CAST")
        return bus[key] as Event<T>
    }

    interface Event<T> {

        /**
         * 发送一个消息，支持前台线程、后台线程发送
         *
         * @param value
         */
        fun post(value: T)

        /**
         * 注册一个Observer，生命周期感知，自动取消订阅
         *
         * @param owner
         * @param observer
         */
        @MainThread
        fun observe(owner: LifecycleOwner, observer: Observer<T>)

        /**
         * 注册一个Observer，生命周期感知，自动取消订阅
         * 如果之前有消息发送，可以在注册时收到最新一条消息
         *
         * @param owner
         * @param observer
         */
        @MainThread
        fun observeSticky(owner: LifecycleOwner, observer: Observer<T>)

        /**
         * 注册一个Observer
         * 不会自动取消订阅，使用者需要手动取消订阅，在不需要调用的时候调用[removeObserver]
         *
         * @param observer
         */
        @MainThread
        fun observeForever(observer: Observer<T>)

        /**
         * 注册一个Observer，如果之前有消息发送，可以在注册时收到最新一条消息
         * 不会自动取消订阅，使用者需要手动取消订阅，在不需要调用的时候调用[removeObserver]
         *
         * @param observer
         */
        @MainThread
        fun observeStickyForever(observer: Observer<T>)

        /**
         * 移除Observer
         *
         * @param observer
         */
        @MainThread
        fun removeObserver(observer: Observer<T>)
    }

    class LiveEvent<T>(key: String) :
        Event<T> {

        private val liveData =
            BusLiveData<T>(key)

        override fun post(value: T) {
            liveData.post(value)
        }

        override fun observe(owner: LifecycleOwner, observer: Observer<T>) {
            liveData.observe(false, owner, observer)
        }

        override fun observeSticky(owner: LifecycleOwner, observer: Observer<T>) {
            liveData.observe(true, owner, observer)
        }

        override fun observeForever(observer: Observer<T>) {
            liveData.observeForever(false, observer)
        }

        override fun observeStickyForever(observer: Observer<T>) {
            liveData.observeForever(true, observer)
        }

        override fun removeObserver(observer: Observer<T>) {
            liveData.removeObserver(observer)
        }
    }

    class BusLiveData<T>(private val key: String) : MutableLiveData<T>() {

        internal var valueVersion = 0
            private set
        private val observerMap = HashMap<Observer<T>, ObserverWrapper<T>>()

        fun observe(isSticky: Boolean, owner: LifecycleOwner, observer: Observer<T>) {
            if (owner.lifecycle.currentState == Lifecycle.State.DESTROYED) {
                return
            }

            if (observerMap.containsKey(observer)) {
                return
            }

            val observerWrapper =
                ObserverWrapper(
                    observer,
                    this,
                    isSticky
                )
            observerMap[observer] = observerWrapper
            super.observe(owner, observerWrapper)
        }

        fun observeForever(isSticky: Boolean, observer: Observer<T>) {
            if (observerMap.containsKey(observer)) {
                return
            }

            val observerWrapper =
                ObserverWrapper(
                    observer,
                    this,
                    isSticky
                )
            observerMap[observer] = observerWrapper
            super.observeForever(observerWrapper)
        }

        override fun removeObserver(observer: Observer<in T>) {
            if (observer is ObserverWrapper) {
                super.removeObserver(observer)
                observerMap.remove(observer.observer)
            } else {
                if (observerMap.containsKey(observer)) {
                    observerMap[observer]?.let { super.removeObserver(it) }
                    observerMap.remove(observer)
                } else {
                    super.removeObserver(observer)
                }
            }

            if (!hasObservers()) {
                // 如果该LiveData没有观察者了，就移除LiveEventBus中的缓存
                instance.bus.remove(key)
            }
        }

        @MainThread
        override fun setValue(value: T) {
            valueVersion++
            super.setValue(value)
        }

        override fun postValue(value: T) {
            valueVersion++
            super.postValue(value)
        }

        private class ObserverWrapper<T>(
            val observer: Observer<T>,
            private val liveData: BusLiveData<T>,
            private val isSticky: Boolean
        ) : Observer<T> {

            private val initVersion = liveData.valueVersion

            override fun onChanged(t: T) {
                if (isSticky) {
                    observer.onChanged(t)
                } else {
                    if (liveData.valueVersion > initVersion) {
                        observer.onChanged(t)
                    }
                }
            }
        }
    }
}

typealias EMPTY_VALUE = Unit
